package com.recruit.recommend.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.recruit.common.common.LocalUser;
import com.recruit.common.mapper.ApplicationMapper;
import com.recruit.common.mapper.FavorMapper;
import com.recruit.common.mapper.PositionMapper;
import com.recruit.common.mapper.UserMapper;
import com.recruit.common.model.ApplicationDO;
import com.recruit.common.model.FavorDO;
import com.recruit.common.model.PositionDO;
import com.recruit.common.model.UserDO;
import com.recruit.common.model.result.PositionResultDO;
import com.recruit.recommend.model.RelateDTO;
import com.recruit.recommend.utils.UserCF;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class RecommendServiceImpl extends ServiceImpl<PositionMapper, PositionDO> implements RecommendService {


    @Resource
    private PositionMapper positionMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private FavorMapper favorMapper;

    @Resource
    private ApplicationMapper applicationMapper;
    /**
     * 推荐岗位（基于协同过滤推荐算法）
     */
    @Override
    public List<PositionResultDO> recommend(Integer num) {
        UserDO currentUser = LocalUser.getLocalUser();
        // 2. 获取所有的岗位信息
        List<PositionResultDO> positions = positionMapper.recommend();
        if (ObjectUtil.isEmpty(currentUser)) {
            // 说明这个时候是游客模式
            return getRandomPositions(num, positions, null);
        }
        // 1. 获取所有的用户信息
        List<UserDO> users = userMapper.selectList(null);
        // 3. 获取所有的收藏信息
        List<FavorDO> collects = favorMapper.selectList(null);
        // 4. 获取所有的投递信息
        List<ApplicationDO> submits = applicationMapper.selectList(null);
        // 存储所有的用户和所有的岗位之间的相关性指数的数据
        List<RelateDTO> data = new ArrayList<>();

        // 开始计算所有用户和所有岗位之间的相关性指数的数据
        for (PositionDO position : positions) {
            Integer positionId = position.getId();
            for (UserDO user : users) {
                Integer userId = user.getId();
                int index = 1;
                // 如果该用户收藏过该岗位，我们权重给他 1
                List<FavorDO> collectList = collects.stream()
                        .filter(x -> x.getPositionId().equals(positionId) && x.getUserId().equals(userId))
                        .collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(collectList)) {
                    index += 1;
                }
                // 如果该用户投递过该岗位，我们权重给他 2
                List<ApplicationDO> submitList = submits.stream()
                        .filter(x -> x.getPositionId().equals(positionId) && x.getUserId().equals(userId))
                        .collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(submitList)) {
                    index += 2;
                }
                if (index > 1) {
                    RelateDTO relateDTO = new RelateDTO(userId, positionId, index);
                    data.add(relateDTO);
                }
            }
        }
        // 调用基于用户行为的UserCF的推荐方法获取到被推荐的岗位的id的list
        List<Integer> positionIds = UserCF.recommend(currentUser.getId(), data);
        // 把list里对应的岗位id变成岗位信息
        List<PositionResultDO> result = positions.stream().filter(x -> positionIds.contains(x.getId())).collect(Collectors.toList());

        // 如果这个推荐出来的list是空的
        if (CollectionUtil.isEmpty(result)) {
            result = getRandomPositions(num, positions, null);
        }
        // 如果推荐的数据不够3个
        if (result.size() < num) {
            result.addAll(getRandomPositions(num - result.size(), positions, result));
        }
        return result;
    }

    public List<PositionResultDO> getRandomPositions(int num, List<PositionResultDO> positions, List<PositionResultDO> result) {
        Collections.shuffle(positions);
        if (CollectionUtil.isNotEmpty(result)) {
            positions = positions.stream().filter(x -> !result.contains(x)).collect(Collectors.toList());
        }

        return positions.size() > num ? positions.subList(0, num) : positions;
    }


}
